home *** CD-ROM | disk | FTP | other *** search
- /* dissMask.c -- Copyright © 1990 by Michael S. Morton. All rights reserved.
-
- History:
- 23-Aug-90 - MM - First public version.
-
- Enhancements needed:
- • Can CopyMask be used with transfer modes with side effects (e.g., additive)?
- If so, we should erase the bitmap before setting each new set of bits.
- */
-
- #include "dissMask.h"
-
- /* Internal prototypes: */
- static void round2 (short *i);
-
- /* Masks to generate the pseudo-random sequence. The
- table runs 0…32, but only elements 2…32 are valid. */
- static unsigned long seqMasks [ /* 0…32 */ ] =
- { 0x0, 0x0, 0x03, 0x06, 0x0C, 0x14, 0x30, 0x60, 0xB8, 0x0110, 0x0240, 0x0500, 0x0CA0,
- 0x1B00, 0x3500, 0x6000, 0xB400, 0x00012000, 0x00020400, 0x00072000, 0x00090000, 0x00140000,
- 0x00300000, 0x00400000, 0x00D80000, 0x01200000, 0x03880000, 0x07200000, 0x09000000,
- 0x14000000, 0x32800000, 0x48000000, 0xA3000000
- };
-
- extern Boolean dissMaskInit (srcRect, info)
- Rect *srcRect; /* INPUT: bounds of source rectangle */
- register dissMaskInfo *info; /* OUTPUT: state-of-the-world for mask */
- {
- /* Copy the client’s source rectangle, then normalize it to (0,0) for simplicity. */
- info->maskRect = *srcRect; /* copy it… */
- OffsetRect (& info->maskRect, /* …and normalize it… */
- -info->maskRect.left, -info->maskRect.top); /* …to (0,0) at the top left */
-
- /* Round it up to a power of two in each dimension for the bitmap’s bounds. This
- speeds up the dissolve considerably by removing bounds checking. Also, ensure
- that the width of the bitmap is a multiple of two bytes, or 16 bits. */
- info->maskMap.bounds = info->maskRect; /* start by copying the client’s bounds */
- round2 (& info->maskMap.bounds.bottom); /* now round both extents… */
- round2 (& info->maskMap.bounds.right); /* …up to powers of two */
- if (info->maskMap.bounds.right < 16) /* too small to be a bitmap? */
- info->maskMap.bounds.right = 16; /* yep: round it up */
-
- /* Compute total number of pixels in the mask bitmap; initialize the countdown counter. */
- info->pixLeft = info->maskMap.bounds.bottom * (long) info->maskMap.bounds.right;
-
- /* Figure the magic mask to be used in the dissMaskNext() loop: */
- { register short log2 = 0; /* log base-two of pixel count */
- register unsigned long ct; /* working copy of pixel count */
-
- ct = info->pixLeft;
- while (ct > 1) /* until log2(ct) == 0 */
- { ct >>= 1; ++log2; } /* …shift it down one; bump log2 */
-
- /* Actually, I don’t think either of these (<2 or >32) can happen… */
- if ((log2 < 2) || (log2 > 32)) /* outside of table bounds? */
- return FALSE; /* can’t do this; client should CopyBits() */
- info->seqMask = seqMasks [log2]; /* set up the mask which generates cycle of length 2**log2 */
- }
-
- /* Because we count iterations, we needn’t watch the sequence element: it can start anywhere. */
- info->seqElement = 1; /* init sequence element to any nonzero value */
-
- /* Finish filling in the pixmap; handle allocation failure. */
- info->maskMap.rowBytes = info->maskMap.bounds.right / 8;
- info->maskMap.baseAddr = NewPtrClear (info->pixLeft / 8); /* allocate data for bitmap */
- if (! info->maskMap.baseAddr) /* allocation failed? */
- return FALSE; /* tell client [should we clear MemErr?] */
-
- --info->pixLeft; /* kludge: one element is done outside loop */
- return TRUE; /* client can continue */
- } /* end of dissMaskInit () */
-
- extern void dissMaskNext (info, steps)
- register dissMaskInfo *info; /* UPDATE: state-of-the-world for mask */
- register unsigned long steps; /* INPUT: number of steps to take */
- { register unsigned long element, mask; /* for use in asm{} */
- register void *baseAddr; /* for use in asm{} */
-
- if (steps == 0) steps = 1; /* keep things sane */
- if (steps > info->pixLeft) /* more steps than we need? */
- steps = info->pixLeft; /* yes: just go ’til the end */
- info->pixLeft -= steps; /* debit this before we trash “steps” */
-
- element = info->seqElement; /* move these… */
- mask = info->seqMask; /* …memory-based variables… */
- baseAddr = info->maskMap.baseAddr; /* …into registers for asm {} */
-
- --steps; /* set up counter to run out at -1, not 0, for DBRA rules */
-
- /* If all the arithmetic can be done in 16 bits, we do so: */
- if ((info->seqMask & 0xffff) == info->seqMask)
- asm
- { /* Sixteen-bit case: “.w” operands and a simple DBRA to wind it up. */
- @loopStart16:
- /* Set the bit for the current sequence element: */
- move.w element, D0 /* copy bit number… */
- move.b D0, D1 /* and make a copy for numbering within a byte */
- lsr.w #3, D0 /* convert bit number to byte number */
- bset D1, 0(baseAddr, D0.w) /* set D1’st bit in D0’th byte of contiguous bitmap */
-
- /* Advance to the next sequence element. If this element was 1, we’re all done. */
- lsr.w #1, element /* throw out a bit… */
- bcc.s @skipXOR16 /* …if it’s only a zero, don’t XOR */
- eor.w mask, element /* if a one-bit fell off, flip mask-bits */
- @skipXOR16:
- dbra steps, @loopStart16 /* count down steps */
- }
-
- else asm
- { /* Thirty-two-bit case: “.l” operands and a SUB.L to follow up the DBRA: */
- @loopStart32:
- /* Set the bit for the current sequence element: */
- move.l element, D0 /* copy bit number… */
- move.b D0, D1 /* and make a copy for numbering within a byte */
- lsr.l #3, D0 /* convert bit number to byte number */
- bset D1, 0(baseAddr, D0.l) /* set D1’st bit in D0’th byte of contiguous bitmap */
-
- /* Advance to the next sequence element. If this element was 1, we’re all done. */
- lsr.l #1, element /* throw out a bit… */
- bcc.s @skipXOR32 /* …if it’s only a zero, don’t XOR */
- eor.l mask, element /* if a one-bit fell off, flip mask-bits */
- @skipXOR32:
- dbra steps, @loopStart32 /* count down low word of steps */
- sub.l #0x00010000, steps /* low word ran out: check high word */
- bpl.s @loopStart32 /* still ≥ 0: loop some more */
- }
-
- info->seqElement = element; /* update sequence element from asm{}’s changes */
-
- if (! info->pixLeft) /* all general pixels copied? */
- asm /* yes: there’s a special case */
- { bset #0, (baseAddr) /* element 0 never comes up, so set bit #0 in byte #0 */
- }
- } /* end of dissMaskNext () */
-
- extern void dissMaskFinish (info)
- register dissMaskInfo *info; /* UPDATE: struct to clean up */
- { DisposPtr (info->maskMap.baseAddr);
- info->maskMap.baseAddr = 0L; /* lights on for safety */
- } /* end of dissMaskFinish () */
-
- /* round2 -- Round a value up to the next power of two. */
- static void round2 (i)
- register short *i;
- { register short result;
-
- result = 1;
- while (result < *i)
- result <<= 1;
- *i = result;
- } /* end of round2 () */
-